package com.samp.nlp.similarity;

import java.text.DecimalFormat;
import java.util.*;

/**
 * 文本相似度的计算：
 * 1：余弦相似度。
 * 2：Jaccard相似度
 */
public class TextSimilarity {

    /**
     * 计算两个文本的余弦相似度。
     * @param textA 已用空格分好词的文本A。
     * @param textB 已用空格分好词的文本B。
     * @return
     */
    public static Double cosSimilarity(String textA, String textB) throws Exception{
        String[] splitsA = textA.split(" ");
        String[] splitsB = textB.split(" ");
        Set<String> wordsSet = new HashSet<>();
        wordsSet.addAll(Arrays.asList(splitsA));
        wordsSet.addAll(Arrays.asList(splitsB));
        int[] vectorA = transText2Vec(splitsA, wordsSet);
        int[] vectorB = transText2Vec(splitsB, wordsSet);
        System.out.println(textA+ " => "+Arrays.toString(vectorA));
        System.out.println(textB+ " => "+Arrays.toString(vectorB));
        return calCosine(vectorA, vectorB);
    }

    public static Double jaccardSimilarity(String textA, String textB) throws Exception{
        String[] splitsA = textA.split(" ");
        String[] splitsB = textB.split(" ");
        List listA = Arrays.asList(splitsA);
        List listB = Arrays.asList(splitsB);
        Set<String> tempSet = new HashSet<>();
        tempSet.addAll(listA);
        tempSet.retainAll(listB);
        System.out.println("交集为："+tempSet);
        int intersectionSize = tempSet.size();
        tempSet.clear();
        tempSet.addAll(listA);
        tempSet.addAll(listB);
        System.out.println("并集为："+tempSet);
        int unionSetSize = tempSet.size();
        System.out.println("intersectionSize="+intersectionSize+", unionSetSize="+unionSetSize);
        Double jac = intersectionSize*1.0/unionSetSize;
        return formatDouble(jac);
    }

    private static Double calCosine(int[] vectorA, int[] vectorB) throws Exception{
        if( vectorA == null || vectorB == null || vectorA.length != vectorB.length ){
            throw new Exception("参数错误");
        }
        Long numerator = 0l;
        Long squarA = 0l;
        Long squarB = 0l;
        for( int i = 0 ;i < vectorA.length ; i++ ){
            numerator += vectorA[i]*vectorB[i];
            squarA += vectorA[i]*vectorA[i];
            squarB += vectorB[i]*vectorB[i];
        }
        if( squarA*squarB == 0 ){
            throw new Exception("denominator is 0");
        }
        Double cos = numerator / Math.sqrt(squarA*squarB);
        return formatDouble(cos);
    }

    private static Double formatDouble(Double num){
        DecimalFormat df=new DecimalFormat("#.####");
        return Double.parseDouble(df.format(num));
    }

    private static int[] transText2Vec(String[] words, Set<String> totalWords){
        int[] vector = new int[totalWords.size()];
        int index = 0;
        for( String s:totalWords ){
            int count = 0 ;
            for(String w:words){
                if( s.equals(w) ){
                    count++;
                }
            }
            vector[index] = count;
            index++;
        }
        return vector;
    }

    public static void main(String[] args) {
        String callMethod = "jaccardSimilarity";
        try{
            String textA = "今天 天气 很 不错";
            String textB = "今天 天气 很 好";
            if( "calCosine".equals(callMethod) ){
                int[] v1 = {1,2,3};
                int[] v2 = {2,3,4};
                System.out.println(calCosine(v1, v2));
            }
            if( "cosSimilarity".equals(callMethod) ){
                System.out.println(cosSimilarity(textA, textB));
            }
            if( "jaccardSimilarity".equals(callMethod) ){
                System.out.println(jaccardSimilarity(textA, textB));
            }
        }catch (Exception e){

        }
    }
}
